home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / elecmail / uupc11ys.zip / MAIL / DELIVER.C < prev    next >
C/C++ Source or Header  |  1993-04-16  |  42KB  |  1,092 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    d e l i v e r  . c                                              */
  3. /*                                                                    */
  4. /*    UUPC/extended mail delivery subroutines                         */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*--------------------------------------------------------------------*/
  18. /*                          RCS Information                           */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*
  22.  *    $Id: DELIVER.C 1.7 1993/04/16 12:55:36 dmwatt Exp $
  23.  *
  24.  *    $Log: DELIVER.C $
  25.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  26.  * Windows/NT sound support
  27.  *
  28.  * Revision 1.6  1993/04/15  03:17:21  ahd
  29.  * Basic bounce support
  30.  *
  31.  * Revision 1.5  1993/04/11  00:33:05  ahd
  32.  * Global edits for year, TEXT, etc.
  33.  *
  34.  * Revision 1.4  1992/12/18  13:05:18  ahd
  35.  * Use one token on request line for UUCP
  36.  *
  37.  * Revision 1.3  1992/12/05  23:38:43  ahd
  38.  * Skip blanks as well as unprintable characters
  39.  *
  40.  * Revision 1.2  1992/12/04  01:00:27  ahd
  41.  * Add system alias support
  42.  *
  43.  */
  44.  
  45. /*--------------------------------------------------------------------*/
  46. /*    Embedded Japanese support provided by Kenji Rikitake            */
  47. /*    28-AUG-1991                                                     */
  48. /*                                                                    */
  49. /*    On Japanese support:                                            */
  50. /*                                                                    */
  51. /*    Japanese MS-DOS uses a 2byte Kanji (Japanese ideogram) code     */
  52. /*    called "Shift-JIS".  This cannot be delivered via SMTP since    */
  53. /*    Shift-JIS maps its first byte from 0x80-0x9f and 0xe0-0xfc.     */
  54. /*    JUNET requests all hosts to send Kanji in a 7bit subset of      */
  55. /*    ISO2022.  This is commonly called "JIS 7bit".                   */
  56. /*                                                                    */
  57. /*    To provide Japanese functionality, you need to convert all      */
  58. /*    remote delivery messages to JIS 7bit, and all local delivery    */
  59. /*    messages to Shift-JIS.                                          */
  60. /*--------------------------------------------------------------------*/
  61.  
  62. /*--------------------------------------------------------------------*/
  63. /*    Use a complex beep upon mail delivery if way to control the     */
  64. /*    speaker is available; if using MS C 6.0 under DOS, we can't     */
  65. /*    so don't try                                                    */
  66. /*--------------------------------------------------------------------*/
  67.  
  68. #ifdef __TURBOC__
  69. #define SMARTBEEP
  70. #endif
  71.  
  72. #ifdef FAMILYAPI
  73. #define SMARTBEEP
  74. #endif
  75.  
  76. #ifdef WIN32
  77. #define SMARTBEEP
  78. #endif
  79.  
  80. #define INCLUDE ":include:"
  81.  
  82. /*--------------------------------------------------------------------*/
  83. /*                        System include files                        */
  84. /*--------------------------------------------------------------------*/
  85.  
  86. #include <stdio.h>
  87. #include <stdlib.h>
  88. #include <io.h>
  89. #include <ctype.h>
  90. #include <sys/types.h>
  91. #include <string.h>
  92. #include <process.h>
  93. #include <limits.h>
  94.  
  95. #ifdef __TURBOC__
  96. #include <dos.h>
  97. #endif
  98.  
  99. #ifdef WIN32
  100. #include <windows.h>
  101. #endif
  102.  
  103. #ifdef FAMILYAPI
  104. #include <os2.h>
  105. #endif
  106.  
  107. /*--------------------------------------------------------------------*/
  108. /*                    UUPC/extended include files                     */
  109. /*--------------------------------------------------------------------*/
  110.  
  111. #include "lib.h"
  112. #include "address.h"
  113. #include "deliver.h"
  114. #include "expath.h"
  115. #include "getseq.h"
  116. #include "kanjicnv.h"
  117. #include "hlib.h"
  118. #include "hostable.h"
  119. #include "import.h"
  120. #include "pushpop.h"
  121. #include "security.h"
  122. #include "stater.h"
  123. #include "usertabl.h"
  124. #include "sysalias.h"
  125. #include "timestmp.h"
  126.  
  127. #ifdef SMARTBEEP
  128. #include "ssleep.h"
  129. #endif
  130.  
  131. /*--------------------------------------------------------------------*/
  132. /*        Define current file name for panic() and printerr()         */
  133. /*--------------------------------------------------------------------*/
  134.  
  135. currentfile();
  136.  
  137. /*--------------------------------------------------------------------*/
  138. /*                        Internal prototypes                         */
  139. /*--------------------------------------------------------------------*/
  140.  
  141. static size_t DeliverLocal( const char *input,  /* Input file name    */
  142.                           char *user,     /* Target address           */
  143.                           const boolean sysalias,
  144.                                              /* Already sys alias     */
  145.                           boolean validate); /* Validate/forward
  146.                                                 local mail            */
  147.  
  148. static int DeliverFile( const char *input,
  149.                         const char *mboxname,
  150.                         const long start,
  151.                         const long end,
  152.                         boolean *announce,
  153.                         struct UserTable *userp,
  154.                         const boolean sysalias,  /* Already sys alias     */
  155.                         const boolean validate,
  156.                         const char *user );
  157.  
  158. static void trumpet( const char *tune);
  159.  
  160. static size_t DeliverRemote( const char *input, /* Input file name    */
  161.                              const char *address,  /* Target address  */
  162.                              const char *path);
  163.  
  164. static size_t DeliverGateway(   const char *input,
  165.                                 const char *user,
  166.                                 const char *node,
  167.                                 const struct HostTable *hostp);
  168.  
  169. static int CopyData(   const boolean remotedelivery,
  170.                        const char *input,
  171.                        FILE *mbox);
  172.  
  173. static char *stats( const char *fname );
  174.  
  175. size_t Bounce( const char *input,
  176.                const char *text,
  177.                const char *data,
  178.                const char *address );
  179.  
  180. /*--------------------------------------------------------------------*/
  181. /*   Global (set by rmail.c) for number of hops this mail has seen    */
  182. /*--------------------------------------------------------------------*/
  183.  
  184.  INTEGER hops = 0;
  185.  
  186.  boolean remoteMail = FALSE;
  187.  
  188.  char *ruser = NULL;
  189.  char *rnode = NULL;
  190.  char *uuser = NULL;
  191.  
  192. /*--------------------------------------------------------------------*/
  193. /*    D e l i v e r                                                   */
  194. /*                                                                    */
  195. /*    Deliver mail to one user                                        */
  196. /*--------------------------------------------------------------------*/
  197.  
  198. size_t Deliver(       const char *input,    /* Input file name       */
  199.                             char *address,  /* Target address           */
  200.                       const boolean sysalias,  /* Already sys alias     */
  201.                           boolean validate)  /* Validate/forward
  202.                                                 local mail            */
  203. {
  204.    char node[MAXADDR];
  205.    char path[MAXADDR];
  206.    char user[MAXADDR];
  207.    char *token;
  208.    struct HostTable *hostp;
  209.  
  210.    if ( strlen( address ) >= MAXADDR )
  211.       return Bounce( input, "Excessive address length", address, address );
  212.  
  213.    user_at_node(address, path, node, user);
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*                       Handle local delivery                        */
  217. /*--------------------------------------------------------------------*/
  218.  
  219.    if (equal(path, E_nodename)) /* Local node?                       */
  220.    {
  221.       struct HostTable *hostx = checkname( node );
  222.       if (hostx->hstatus == localhost)  /* Really the local node?    */
  223.          return DeliverLocal( input, user, sysalias, validate );
  224.                                  /* Yes!                             */
  225.       else
  226.          Bounce( input,
  227.                  "No delivery path for address",
  228.                   address,
  229.                   address );
  230.    }  /* if */
  231.  
  232. /*--------------------------------------------------------------------*/
  233. /*                    Do we need loop protection?                     */
  234. /*--------------------------------------------------------------------*/
  235.  
  236.    if (hops > E_maxhops)
  237.       Bounce(input, "Excessive number of hops", address, address );
  238.  
  239. /*--------------------------------------------------------------------*/
  240. /*                   Deliver to a gateway if needed                   */
  241. /*--------------------------------------------------------------------*/
  242.  
  243.    hostp = checkname( path );
  244.    if ( (hostp != BADHOST) && (hostp->hstatus == gatewayed))
  245.       return DeliverGateway( input, user, node, hostp );
  246.  
  247. /*--------------------------------------------------------------------*/
  248. /*         Deliver mail to a system directory connected to us         */
  249. /*--------------------------------------------------------------------*/
  250.  
  251.    if (equal(path,node))   /* Directly connected system?          */
  252.       return DeliverRemote( input, user, path); /* Yes            */
  253.  
  254. /*--------------------------------------------------------------------*/
  255. /*   Default delivery; strip any this node and the directly           */
  256. /*   connected system from the address, then deliver to the next      */
  257. /*   hop on the route                                                 */
  258. /*--------------------------------------------------------------------*/
  259.  
  260.    strcpy(node,address);
  261.    token = strtok(node,"!");  /* Get first host in path        */
  262.    if (equal( HostAlias(token), E_nodename)) /* Local system?  */
  263.    {
  264.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  265.       strcpy(address, token);    /* Use it for address         */
  266.       token = strtok(token,"!"); /* Get next host in path      */
  267.    } /* if */
  268.  
  269.    if (equal( HostAlias(token), path ))  /* Next system?       */
  270.    {
  271.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  272.       strcpy(address, token);    /* Use it for address         */
  273.    } /* if */
  274.  
  275.    if (!strpbrk(address,"!@"))   /* Any host delimiters?       */
  276.    {                             /* No --> Check for % routing */
  277.       token = strrchr(address,'%'); /* Get last percent sign   */
  278.       if (token != NULL)
  279.          *token = '@';           /* Make it an RFC-822 address */
  280.       else
  281.          printmsg(0,"Deliver: Cannot find node in \"%s\"",
  282.                address);         /* That's odd, it should not  */
  283.                                  /* be a local address!        */
  284.    } /* if */
  285.  
  286.    return DeliverRemote( input, address, path );
  287.  
  288. } /* Deliver */
  289.  
  290. /*--------------------------------------------------------------------*/
  291. /*    D e l i v e r L o c a l                                         */
  292. /*                                                                    */
  293. /*    Handle local delivery, including optional forwarding            */
  294. /*--------------------------------------------------------------------*/
  295.  
  296. static size_t DeliverLocal( const char *input,
  297.                                           /* Input file name          */
  298.                           char *user,     /* Target address           */
  299.                           const boolean sysalias,
  300.                                           /* Already sys alias     */
  301.                           boolean validate)  /* TRUE = validate,
  302.                                                 forward user's mail   */
  303. {
  304.    char mboxname[FILENAME_MAX];
  305.    struct UserTable *userp = NULL;
  306.    ALIASTABLE *aliasp = NULL;
  307.    int delivered = 0;
  308.    boolean announce = FALSE;
  309.    FILE *mbox;
  310.  
  311. /*--------------------------------------------------------------------*/
  312. /*    If the parameter is the postmaster, use the configuration       */
  313. /*    defined value for the postmaster                                */
  314. /*--------------------------------------------------------------------*/
  315.  
  316.    if (equali(user, POSTMASTER))
  317.       user = E_postmaster;
  318.  
  319. /*--------------------------------------------------------------------*/
  320. /*             Validate user id and check for forwarding              */
  321. /*--------------------------------------------------------------------*/
  322.  
  323.    if (validate)
  324.    {
  325.       validate = strcmp( E_postmaster , user);
  326.                                  /* Don't loop delivering to postmast*/
  327.  
  328.       userp = checkuser(user);   /* Locate user id in host table     */
  329.  
  330. /*--------------------------------------------------------------------*/
  331. /*                     Process any system aliases                     */
  332. /*--------------------------------------------------------------------*/
  333.  
  334.       if ( ! sysalias )
  335.       {
  336.          aliasp = checkalias( user );  /* System alias?             */
  337.  
  338.          if ( aliasp != NULL )
  339.          {
  340.             delivered += DeliverFile( input,
  341.                                       SysAliases,
  342.                                       aliasp->start,
  343.                                       aliasp->end,
  344.                                       &announce ,
  345.                                       userp,
  346.                                       TRUE,
  347.                                       validate,
  348.                                       user );
  349.  
  350.             if ( announce && ( userp != BADUSER ))
  351.                trumpet( userp->beep);  /* Yes --> Inform the user    */
  352.             return delivered;
  353.  
  354.          } /* if */
  355.       } /* if */
  356.  
  357. /*--------------------------------------------------------------------*/
  358. /*             No system alias, verify the user is valid              */
  359. /*--------------------------------------------------------------------*/
  360.  
  361.       if ( userp == BADUSER )    /* Invalid user id?                 */
  362.       {                          /* Yes --> Dump in trash bin        */
  363.          return Bounce( input, "Invalid local user", user, user );
  364.       } /* if */
  365.  
  366. /*--------------------------------------------------------------------*/
  367. /*               The user id validated; handle the mail               */
  368. /*--------------------------------------------------------------------*/
  369.  
  370.       mkfilename(mboxname, userp->homedir, DOTFORWARD);
  371.  
  372.       if (access( mboxname, 0 )) /* The .forward file exists?        */
  373.          announce = TRUE;        /* No --> Fall through              */
  374.       else {
  375.          delivered += DeliverFile( input,
  376.                                    mboxname,
  377.                                    0,
  378.                                    LONG_MAX,
  379.                                    &announce,
  380.                                    userp,
  381.                                    FALSE,
  382.                                    validate,
  383.                                    user );
  384.  
  385.          if (announce)        /* Did we deliver mail locally?        */
  386.             trumpet( userp->beep);  /* Yes --> Inform the user       */
  387.          return delivered;
  388.  
  389.       } /* if */
  390.  
  391.    } /* if (validate) */
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*       The user is valid (or not validated) and not forwarded       */
  395. /*--------------------------------------------------------------------*/
  396.  
  397.    if ((*user == '/') || (isalpha( *user ) && user[1] == ':'))
  398.                               /* Absolute path from recursive call?   */
  399.       strcpy(mboxname, user); /* Yes --> Use it as-is                 */
  400.    else
  401.       mkmailbox(mboxname, user);
  402.                               /* No --> Build normal name             */
  403.  
  404.    printmsg(1,"Delivering mail %sfrom %s%s%s to %s",
  405.                         stats( input ),
  406.                         ruser,
  407.                         remoteMail ? "@" : "",
  408.                         remoteMail ? rnode : "",
  409.                          user );
  410.  
  411.    if ( announce )
  412.       trumpet( userp->beep);  /* Local delivery, inform the user     */
  413.  
  414.    mbox = FOPEN( mboxname , "a",TEXT_MODE );
  415.    if (mbox == NULL )
  416.    {
  417.       printerr(mboxname);
  418.       printmsg(0,"Cannot open mailbox \"%s\" for output",
  419.                   mboxname);
  420.       panic();
  421.    }
  422.  
  423.    if (!isatty(fileno(mbox)))
  424.       fputs(MESSAGESEP,mbox); /* Write separator line                 */
  425.  
  426.    return CopyData( FALSE, input , mbox );
  427.  
  428. } /* DeliverLocal */
  429.  
  430. /*--------------------------------------------------------------------*/
  431. /*       D e l i v e r F i l e                                        */
  432. /*                                                                    */
  433. /*       Process a local or system aliases file                       */
  434. /*--------------------------------------------------------------------*/
  435.  
  436. static int DeliverFile( const char *input,
  437.                         const char *fwrdname,
  438.                         const long start,
  439.                         const long end,
  440.                         boolean *announce,
  441.                         struct UserTable *userp,
  442.                         const boolean sysalias,  /* Already sys alias     */
  443.                         const boolean validate,
  444.                         const char *user )
  445. {
  446.    char buf[BUFSIZ];
  447.    FILE *fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  448.    int delivered = 0;
  449.  
  450.    if ( fwrd == NULL )
  451.    {
  452.       printerr( fwrdname );
  453.       return Bounce( input, "Cannot open forward file", fwrdname, user );
  454.    }
  455.  
  456.    if ( start != 0 )
  457.       fseek( fwrd, start, SEEK_SET);
  458.  
  459.    while((ftell(fwrd) < end) && (fgets( buf , BUFSIZ , fwrd) != NULL ))
  460.    {
  461.       char command[BUFSIZ];
  462.       char *s = buf;
  463.       char c;
  464.       char *nextfile = NULL;
  465.  
  466.       if ( buf[ strlen(buf) - 1 ]== '\n')
  467.          buf[ strlen(buf) - 1 ] = '\0';
  468.  
  469.       while( *s && ! isgraph( *s ))    /* Trim leading white space      */
  470.          s++;
  471.  
  472.       printmsg(8,"Forwarding to \"%s\"", s);
  473.       if ( equalni( buf, INCLUDE, strlen(INCLUDE)))
  474.       {
  475.          nextfile = strtok( s + strlen(INCLUDE), WHITESPACE );
  476.          if ( nextfile == NULL )
  477.          {
  478.             return Bounce(input,
  479.                           "Missing forwarding file for alias",
  480.                           fwrdname,
  481.                           user );
  482.          }
  483.          else
  484.             c = ':';
  485.       } /* if */
  486.       else if ( isalpha(*s ) && (s[1] == ':'))  /* Drive name?    */
  487.          c = '/';             /* Yes --> flag as absolute path    */
  488.       else if ( *s == ':')    /* Avoid false triggers ...         */
  489.          c = ' ';             /* ... by making it general case    */
  490.       else                    /* Handle other cases in switch ... */
  491.          c = *s;
  492.  
  493.       switch(c)
  494.       {
  495.          case '#':
  496.             break;            /* Comment, ignore            */
  497.  
  498.          case '\0':
  499.             break;            /* Empty line, ignore         */
  500.  
  501.          case '|':               /* Pipe mail into a command   */
  502.          {
  503.             long here = ftell(fwrd);
  504.             fclose(fwrd);
  505.             sprintf(command , "%s < %s", &s[1], input);
  506.             printmsg(1,"Executing \"%s\" in %s",
  507.                   command, userp->homedir);
  508.             PushDir( userp->homedir );
  509.             system(command);                 /* FIX THIS */
  510.             PopDir();
  511.             delivered += 1;
  512.             fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  513.             fseek( fwrd, here, SEEK_SET);
  514.             break;
  515.          } /* case */
  516.  
  517.          case '\\':              /* Deliver without forwarding */
  518.             delivered += Deliver( input, &s[1], TRUE, FALSE );
  519.             *announce = TRUE;
  520.             break;
  521.  
  522.          case ':':
  523.             delivered += DeliverFile( input, nextfile, 0, LONG_MAX,
  524.                                       announce, userp,
  525.                                       FALSE, TRUE, user );
  526.             break;
  527.  
  528.          case '/':               /* Save in absolute path name */
  529.          case '~':
  530.             if (expand_path(s, NULL, userp->homedir,
  531.                             E_mailext) == NULL )
  532.             {
  533.                return Bounce(input,
  534.                              "Invalid path in forwarding file name",
  535.                              s,
  536.                              user );
  537.  
  538.             }
  539.             else
  540.                delivered += DeliverLocal( input, s, sysalias, FALSE );
  541.             *announce = TRUE;
  542.             break;
  543.  
  544.          default:                /* Deliver normally           */
  545.               delivered += Deliver( input, s, sysalias, validate );
  546.       } /* switch */
  547.    } /* while */
  548.  
  549.    fclose( fwrd );
  550.  
  551.    return delivered;
  552.  
  553. } /* DeliverFile */
  554.  
  555.  
  556. /*--------------------------------------------------------------------*/
  557. /*    t r u m p e t                                                   */
  558. /*                                                                    */
  559. /*    Trumpet the arrival of remote mail to a local user              */
  560. /*--------------------------------------------------------------------*/
  561.  
  562. static void trumpet( const char *tune)
  563. {
  564. #ifdef SMARTBEEP
  565.    char buf[BUFSIZ];
  566.    char *token = buf;
  567.    size_t tone, duration;
  568. #endif
  569.  
  570.    if ((tune == NULL) || !remoteMail) /* Should we announce?  */
  571.       return;                 /* No --> Return quietly (literally)   */
  572.  
  573. /*--------------------------------------------------------------------*/
  574. /*             We are to announce the arrival of the mail             */
  575. /*--------------------------------------------------------------------*/
  576.  
  577. #ifdef SMARTBEEP
  578.    strcpy(buf,tune);          /* Save the data                       */
  579.  
  580.    while( (token = strtok( token, ",")) != NULL)
  581.    {
  582.       tone = (size_t) atoi(token);
  583.       token = strtok( NULL, ",");
  584.       duration = (token == NULL) ? 500 : (size_t) atoi(token);
  585.  
  586. #ifdef __TURBOC__
  587.       if (tone == 0)
  588.          nosound();
  589.       else
  590.          sound( tone );
  591.       ddelay( duration );
  592. #else
  593.       if (tone == 0)
  594.          ddelay(duration);
  595.       else {
  596. #ifdef WIN32
  597.          Beep( tone, duration );
  598. #else
  599.          DosBeep( tone, duration );
  600. #endif
  601.       }
  602. #endif /* __TURBOC__ */
  603.  
  604.       token = NULL;           /* Look at next part of string   */
  605.    } /* while */
  606.  
  607. #ifdef __TURBOC__
  608.    nosound();
  609. #endif
  610. #else /* SMARTBEEP */
  611.  
  612. /*--------------------------------------------------------------------*/
  613. /*      We cannot play the requested tune; just beep at the user      */
  614. /*--------------------------------------------------------------------*/
  615.  
  616.    fputc('\a', stdout);
  617. #endif /* SMARTBEEP */
  618.  
  619. } /* trumpet */
  620.  
  621. /*--------------------------------------------------------------------*/
  622. /*    D e l i v e r G a t e w a y                                     */
  623. /*                                                                    */
  624. /*    Deliver mail via a gateway program                              */
  625. /*--------------------------------------------------------------------*/
  626.  
  627. static size_t DeliverGateway(   const char *input,
  628.                                 const char *user,
  629.                                 const char *node,
  630.                                 const struct HostTable *hostp)
  631. {
  632.    char command[BUFSIZ];
  633.  
  634. /*--------------------------------------------------------------------*/
  635. /*    Format the command and tell the user what we're going to do     */
  636. /*--------------------------------------------------------------------*/
  637.  
  638.    sprintf(command , "%s %s %s %s < %s",
  639.                      hostp->via,          /* Program to perform forward */
  640.                      hostp->hostname,     /* Nominal host routing via   */
  641.                      node ,               /* Final destination system   */
  642.                      user,                /* user on "node" for delivery*/
  643.                      input);              /* The data to forward        */
  644.  
  645.    printmsg(1,
  646.       "Gatewaying mail %sfrom %s@%s to %s@%s via %s using \"%s\"",
  647.        stats( input ),
  648.        ruser, rnode, user, node, hostp->hostname, hostp->via);
  649.    printmsg(3,"DeliverGateway: %s",command);
  650.  
  651. /*--------------------------------------------------------------------*/
  652. /*  Run the command and return caller with count of mail delivered    */
  653. /*--------------------------------------------------------------------*/
  654.  
  655.    system(command);
  656.    return 1;
  657.  
  658. } /* DeliveryGateway */
  659.  
  660. /*--------------------------------------------------------------------*/
  661. /*    D e l i v e r R e m o t e                                       */
  662. /*                                                                    */
  663. /*    Queue mail for delivery on another system via UUCP              */
  664. /*--------------------------------------------------------------------*/
  665.  
  666. static size_t DeliverRemote( const char *input, /* Input file name    */
  667.                     const char *address,  /* Target address           */
  668.                     const char *path)
  669. {
  670.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  671.    static char *dataf_fmt = DATAFFMT;
  672.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  673.    static long seqno = 0;
  674.    static char *SavePath = NULL;
  675.    FILE *stream;              /* For writing out data                */
  676.    static char everyone[500]; /* 512, with room for "rmail "         */
  677.  
  678.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files         */
  679.    char msname[22];           /* MS-DOS format w/o path name         */
  680.  
  681.    char tmfile[15];           /* Call file, UNIX format name         */
  682.    static char ixfile[15];    /* eXecute file for remote system,
  683.                                 UNIX format name for local system   */
  684.    static char idfile[15];    /* Data file, UNIX format name         */
  685.    static char rdfile[15];    /* Data file name on remote system,
  686.                                  UNIX format                         */
  687.    static char rxfile[15];    /* Remote system UNIX name of eXecute
  688.                                  file                                */
  689.  
  690.    printmsg(1,"Spooling mail %sfrom %s%s%s to %s via %s",
  691.                stats( input ),
  692.                ruser,
  693.                remoteMail ? "@" : "",
  694.                remoteMail ? rnode : "",
  695.                address ,
  696.                path);
  697.  
  698. /*--------------------------------------------------------------------*/
  699. /*          Create the UNIX format of the file names we need          */
  700. /*--------------------------------------------------------------------*/
  701.  
  702.    if ((seqno == 0) ||
  703.        (SavePath == NULL) ||
  704.        !equal(SavePath, path) ||
  705.        ((int) (strlen(everyone) + strlen(address) + 2) > (int) sizeof everyone))
  706.    {
  707.       char *seq;
  708.       seqno = getseq();
  709.       seq = JobNumber( seqno );
  710.  
  711.       if  (SavePath != NULL )
  712.       {
  713.          free(SavePath);
  714.          SavePath = NULL;
  715.       } /* if */
  716.  
  717.       sprintf(tmfile, spool_fmt, 'C', path,     'C' , seq);
  718.       sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  719.       sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  720.       sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  721.       sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  722.       strcpy(everyone,address);
  723.  
  724.    } /* if */
  725.    else {
  726.       strcat(everyone," ");
  727.       strcat(everyone,address);
  728.    } /* else */
  729.  
  730. /*--------------------------------------------------------------------*/
  731. /*                     create remote X (xqt) file                     */
  732. /*--------------------------------------------------------------------*/
  733.  
  734.    importpath( msname, ixfile, path);
  735.    mkfilename( msfile, E_spooldir, msname);
  736.  
  737.    stream = FOPEN(msfile, "w", BINARY_MODE);
  738.    if ( stream == NULL )
  739.    {
  740.       printerr(msfile);
  741.       printmsg(0, "DeliverRemote: cannot open X file %s", msfile);
  742.       return 0;
  743.    } /* if */
  744.  
  745.  
  746.    fprintf(stream, "R %s@%s\nU %s %s\nF %s\nI %s\nC rmail %s\n",
  747.                ruser, rnode, uuser , E_nodename,
  748.                rdfile, rdfile, everyone);
  749.    fclose(stream);
  750.  
  751.    if (SavePath != NULL)
  752.       return 1;
  753.  
  754. /*--------------------------------------------------------------------*/
  755. /*  Create the data file with the mail to send to the remote system   */
  756. /*--------------------------------------------------------------------*/
  757.  
  758.    importpath(msname, idfile, path);
  759.    mkfilename( msfile, E_spooldir, msname);
  760.  
  761.    stream = FOPEN(msfile, "w", BINARY_MODE);
  762.    if (stream == NULL )
  763.    {
  764.       printerr(msfile);
  765.       printmsg(0,
  766.                "DeliverRemote: Cannot open spool file \"%s\" for output",
  767.                 msfile);
  768.       return 0;
  769.    }
  770.  
  771.    if (!CopyData( TRUE, input , stream ))
  772.    {
  773.       remove( msfile );
  774.       return 0;
  775.    }
  776.  
  777. /*--------------------------------------------------------------------*/
  778. /*                     create local C (call) file                     */
  779. /*--------------------------------------------------------------------*/
  780.  
  781.    importpath( msname, tmfile, path);
  782.    mkfilename( msfile, E_spooldir, msname);
  783.  
  784.    stream = FOPEN(msfile, "w",TEXT_MODE);
  785.    if (stream == NULL)
  786.    {
  787.       printerr( msname );
  788.       printmsg(0, "DeliverRemote: cannot open C file %s", msfile);
  789.       return 0;
  790.    }
  791.  
  792.    fprintf(stream, send_cmd, idfile, rdfile, uuser, idfile);
  793.    fprintf(stream, send_cmd, ixfile, rxfile, uuser, ixfile);
  794.    fclose(stream);
  795.  
  796.    if (bflag[F_MULTI])        /* Deliver to multiple users at once?  */
  797.       SavePath = strdup(path);   /* Yes --> Save routing info        */
  798.  
  799.    return 1;
  800. } /* DeliverRemote */
  801.  
  802. /*--------------------------------------------------------------------*/
  803. /* C o p y D a t a                                                    */
  804. /*                                                                    */
  805. /* Copy data into its final resting spot                              */
  806. /*--------------------------------------------------------------------*/
  807.  
  808. static int CopyData( const boolean remotedelivery,
  809.                      const char *input,
  810.                      FILE *dataout)
  811. {
  812.    FILE *datain = FOPEN(input, "r",TEXT_MODE);
  813.    char buf[BUFSIZ];
  814.    int column = 0;
  815.    boolean success = TRUE;
  816.  
  817.    int (*put_string) (char *, FILE *) = (int (*)(char *, FILE *)) fputs;
  818.                               /* Assume no Kanji translation needed  */
  819.  
  820. /*--------------------------------------------------------------------*/
  821. /*                      Verify the input opened                       */
  822. /*--------------------------------------------------------------------*/
  823.  
  824.    if (datain == NULL)
  825.    {
  826.       printerr(input);
  827.       printmsg(0,"Unable to open input file \"%s\"", input);
  828.       fclose(dataout);
  829.       return 0;
  830.    } /* datain */
  831.  
  832. /*--------------------------------------------------------------------*/
  833. /*    When we do the From line, we also determine if we must          */
  834. /*    translate the data.  Note that the default is initialized to    */
  835. /*    fputs() above.                                                  */
  836. /*                                                                    */
  837. /*    If Kanji is not enabled, don't translate it                     */
  838. /*                                                                    */
  839. /*    If local mail queued for local delivery, the data is already    */
  840. /*    in Shift JIS, so don't translate it.                            */
  841. /*                                                                    */
  842. /*    If remote mail is queued for remote delivery, the data is       */
  843. /*    already in JIS 7bit, so don't translate it.                     */
  844. /*                                                                    */
  845. /*    If delivering remote mail locally, translate to Shift JIS       */
  846. /*                                                                    */
  847. /*    If delivering local mail remotely, translate to JIS 7 bit       */
  848. /*--------------------------------------------------------------------*/
  849.  
  850. /*--------------------------------------------------------------------*/
  851. /*                        Generate a FROM line                        */
  852. /*--------------------------------------------------------------------*/
  853.  
  854.    switch( (int) remoteMail * 2 + (int) remotedelivery )
  855.    {
  856.       case 3:                 /* Remote sender, remote delivery      */
  857.          strcpy( buf, fromuser );
  858.          strtok( buf, "!");   /* Get first host in list              */
  859.  
  860.          if ( equal(HostAlias( buf ), fromnode ))
  861.                               /* Host already in list?               */
  862.          {                    /* Yes --> Don't do it twice           */
  863.             fprintf(dataout, "From %s %s remote from %s\n",
  864.                      fromuser, now, E_nodename);
  865.             break;
  866.          }
  867.          else {                /* No --> Insert it                    */
  868.             fprintf(dataout, "From %s!%s %s remote from %s\n",
  869.                      fromnode, fromuser, now, E_nodename);
  870.             break;
  871.          }
  872.  
  873. /*--------------------------------------------------------------------*/
  874. /*    Note:  For the Kanji translation we re-check the                */
  875. /*    remoteDelivery flag since we do the fall through from above.    */
  876. /*--------------------------------------------------------------------*/
  877.  
  878.       case 2:                 /* Remote sender, local delivery       */
  879.          if ( bflag[ F_KANJI ] )
  880.                               /* Kanji from remote node?             */
  881.             put_string = (int (*)(char *, FILE *)) fputs_shiftjis;
  882.                               /* Yes --> Translate it                */
  883.  
  884.          fprintf(dataout, "From %s %s remote from %s\n",
  885.                   fromuser, now, fromnode);
  886.          break;
  887.  
  888.       case 1:                 /* Local sender, remote delivery       */
  889.          if ( bflag[F_KANJI]) /* Translation enabled?                */
  890.             put_string = (int (*)(char *, FILE *)) fputs_jis7bit;
  891.                               /* Translate into 7 bit Kanji          */
  892.  
  893.          column = strlen(E_domain) - 5;
  894.          if ((column > 0) && equali(&E_domain[column],".UUCP"))
  895.                               /* UUCP domain?                        */
  896.             fprintf(dataout, "From %s %s remote from %s\n",
  897.                              fromuser, now, E_nodename);
  898.                               /* Yes --> Use simple address          */
  899.          else
  900.             fprintf(dataout, "From %s!%s %s remote from %s\n",
  901.                   E_domain, fromuser, now, E_nodename);
  902.                               /* No --> Use domain address           */
  903.          break;
  904.  
  905.       case 0:                 /* Local sender, local delivery        */
  906.          fprintf(dataout, "From %s %s\n", fromuser, now);
  907.          break;
  908.  
  909.    } /* switch */
  910.  
  911. /*--------------------------------------------------------------------*/
  912. /*                       Loop to copy the data                        */
  913. /*--------------------------------------------------------------------*/
  914.  
  915.    while (fgets(buf, BUFSIZ, datain) != NULL)
  916.    {
  917.       if ((*put_string)(buf, dataout) == EOF)     /* I/O error? */
  918.       {
  919.          printerr("output");
  920.          printmsg(0,"I/O error on \"%s\"", "output");
  921.          fclose(dataout);
  922.          return 0;
  923.       } /* if */
  924.    } /* while */
  925.  
  926. /*--------------------------------------------------------------------*/
  927. /*                      Close up shop and return                      */
  928. /*--------------------------------------------------------------------*/
  929.  
  930.    if (ferror(datain))        /* Clean end of file on input?         */
  931.    {
  932.       printerr(input);
  933.       clearerr(datain);
  934.       success = FALSE;
  935.    }
  936.  
  937.    fclose(datain);
  938.    fclose(dataout);
  939.    return success;
  940. } /* CopyData */
  941.  
  942. /*--------------------------------------------------------------------*/
  943. /*       b o u n c e                                                  */
  944. /*                                                                    */
  945. /*       Report failed mail to a user.  Based on code contributed     */
  946. /*       by Kevin Meyer <kmeyer@sauron.alt.za>                        */
  947. /*                                                                    */
  948. /*       This code has a major hole in that the address it replies    */
  949. /*       to is weak, really having been previously only been used     */
  950. /*       for internal messages.  Perhaps the full address from the    */
  951. /*       UUCP From line should be used.                               */
  952. /*--------------------------------------------------------------------*/
  953.  
  954. size_t Bounce( const char *input,
  955.                const char *text,
  956.                const char *data,
  957.                const char *address )
  958. {
  959.     FILE *newfile, *otherfile;
  960.     char tname[FILENAME_MAX]; /* name of temporary file used */
  961.     char buf[BUFSIZ];
  962.     char sender[MAXADDR];
  963.  
  964.     boolean bounce = bflag[F_BOUNCE];
  965.  
  966.    sprintf(sender, "%s%s%s",
  967.                ruser,
  968.                remoteMail ? "@" : "",
  969.                remoteMail ? rnode : "" );
  970.  
  971.     printmsg(0,"Bounce: Mail from %s for %s failed, %s: %s",
  972.                sender,
  973.                address,
  974.                text,
  975.                (data == NULL) ? "(no data)" : data );
  976.  
  977. /*--------------------------------------------------------------------*/
  978. /*           Never bounce mail to a select list of user ids           */
  979. /*--------------------------------------------------------------------*/
  980.  
  981.    if ( equali( ruser, "postmaster") ||
  982.         equali( ruser, "uucp") ||
  983.         equali( ruser, "root") ||
  984.         equali( ruser, "mmdf") ||
  985.         equali( ruser, "mailer-daemon"))
  986.      bounce = FALSE;
  987.  
  988.    if ( ! bounce )
  989.      return Deliver( input, E_postmaster, FALSE, TRUE);
  990.  
  991.    mktempname( tname , "TMP");  // Generate a temp file name
  992.  
  993.    if ((otherfile = FOPEN(input,"r", TEXT_MODE ))==NULL)
  994.    {
  995.        printerr( input );
  996.        panic();
  997.    };
  998.  
  999.    if ((newfile = FOPEN(tname, "w", TEXT_MODE ))==NULL)
  1000.    {
  1001.        printerr( tname );
  1002.        panic();
  1003.    };
  1004.  
  1005.    fprintf(newfile,
  1006.      "Dear %s,\n"
  1007.      "Your message for address <%s> could not be delivered at system\n"
  1008.      "%s (uucp node %s) for the following reason:\n\t\t%s.\n",
  1009.                   ruser,
  1010.                   address, E_domain, E_nodename, text );
  1011.  
  1012.    if ( data != NULL )
  1013.       fprintf(newfile,
  1014.              "The problem address or file in question was:  %s\n",
  1015.              data );
  1016.  
  1017.       fprintf(newfile,
  1018.               "\nA copy of the failed mail follows.\n\n"
  1019.               "Electronically Yours,\n"
  1020.               "%s %s UUCP mailer daemon\n",
  1021.               compilep, compilev );
  1022.  
  1023.     fputs("\n------ Failed Message Follows -----\n", newfile);
  1024.  
  1025.      while (!feof(otherfile))
  1026.         fputs(fgets(buf, sizeof buf, otherfile), newfile);
  1027.  
  1028.     fclose(newfile);
  1029.     fclose(otherfile);
  1030.  
  1031. /*--------------------------------------------------------------------*/
  1032. /*                Format the subject, keeping it short                */
  1033. /*--------------------------------------------------------------------*/
  1034.  
  1035.    sprintf( buf, "\"Failed mail for %.20s\"", address );
  1036.  
  1037. /*--------------------------------------------------------------------*/
  1038. /*          Recursively invoke RMAIL to deliver our message           */
  1039. /*--------------------------------------------------------------------*/
  1040.  
  1041.     putenv("LOGNAME=uucp");
  1042.     if (spawnlp(P_WAIT,
  1043.             "rmail",
  1044.             "rmail",
  1045.             "-w",
  1046.             "-F",
  1047.             tname,
  1048.             "-s",
  1049.             buf,
  1050.             sender,
  1051.             "-c",
  1052.             "postmaster", NULL ) == -1 )
  1053.     {
  1054.          printerr("spawn");
  1055.          DeliverLocal( input, E_postmaster, FALSE, FALSE);
  1056.     }
  1057.  
  1058.     return (1);
  1059.  
  1060. } /* Bounce */
  1061.  
  1062.  
  1063. /*--------------------------------------------------------------------*/
  1064. /*    s t a t s                                                       */
  1065. /*                                                                    */
  1066. /*    Report size of file in message, if desired                      */
  1067. /*--------------------------------------------------------------------*/
  1068.  
  1069. static char *stats( const char *fname )
  1070. {
  1071.    if (bflag[ F_COLLECTSTATS ] )
  1072.    {
  1073.       long size;
  1074.       time_t ltime = stater(fname, &size);
  1075.  
  1076.       if ( ltime == -1 )
  1077.       {
  1078.          printerr( fname );
  1079.          return "(unknown size)";
  1080.       }
  1081.       else {
  1082.          static char buf[25];  /* "(nnnnnnn bytes) " */
  1083.                                /*  ....+....+....+.. */
  1084.          sprintf(buf,   "(%ld bytes) ",size );
  1085.          return buf;
  1086.       } /* else */
  1087.    } /* if */
  1088.    else
  1089.       return "";              /* Pretend we were never here       */
  1090.  
  1091. } /* stats */
  1092.